﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using MyBasicLib.Data.ORMLiteNew.Translation;

namespace MyBasicLib.Data.ORMLiteNew
{
    /// <summary>
    /// 查询信息
    /// </summary>
    public sealed class DbQueryInfo
    {
        //  public DbExpression ComputExpression;

        public DbExpression DeleteExpression;
        public InsertDbExpression InsertExpression;
        //public string CountString;
        public bool IsCount;
        public bool IsDistinct;

        public Queue<JoinDbExpression> JoinExpressions = new Queue<JoinDbExpression>();
        public Queue<DbExpression> OrderExpressions = new Queue<DbExpression>();
        public Type ResultType;
        public Expression SelectExpression;
        public int Skip;
        public Type SourceType;
        public int Take;
        public DbExpression UpdateExpression;
        public Queue<Expression> WhereExpression = new Queue<Expression>();
        public TableAliasCache cache = new TableAliasCache();
        private int joinCount;

        public static DbQueryInfo Parse(IList<DbExpression> dbExpressions)
        {
            var info = new DbQueryInfo();

            for (int i = 0; i < dbExpressions.Count; i++)
            {
                DbExpression dbExpression = dbExpressions[i];
                switch (dbExpression.DbExpressionType)
                {
                    case DbExpressionType.None:
                        break;
                    case DbExpressionType.Source:
                        info.SourceType = ((SourceDbExpression) dbExpression).SourceType;
                        break;
                    case DbExpressionType.All:
                        break;
                    case DbExpressionType.Any:
                        break;
                    case DbExpressionType.Average:
                        // info.ComputExpression = dbExpression;
                        break;
                    case DbExpressionType.Count:
                        // info.CountString = " COUNT(*)";
                        info.IsCount = true;
                        info.WhereExpression.Enqueue(((CountDbExpression) dbExpression).Predicate);
                        break;
                    case DbExpressionType.Distinct:
                        info.IsDistinct = true;
                        break;
                    case DbExpressionType.First:
                    case DbExpressionType.FirstOrDefault:
                        info.Take = 1;
                        info.WhereExpression.Enqueue(((FirstDbExpression) dbExpression).Predicate);
                        break;
                    case DbExpressionType.GroupBy:
                        break;
                    case DbExpressionType.GroupJoin:
                    case DbExpressionType.Join:

                        var je = dbExpression as JoinDbExpression;
                        info.SelectExpression = je.ResultSelector;

                        if (info.joinCount++ == 0)
                            info.cache.GetTableAlias(je.OuterKeySelector);
                        info.cache.GetTableAlias(je.InnerKeySelector);

                        if (dbExpressions.Count > i + 1 &&
                            dbExpressions[i + 1].DbExpressionType == DbExpressionType.SelectMany)
                        {
                            info.SelectExpression = ((SelectManyDbExpression) dbExpressions[i + 1]).Selector;

                            je.JoinType = JoinType.LeftJoin;
                            i++;
                        }
                        info.JoinExpressions.Enqueue(je);
                        break;
                    case DbExpressionType.Max:
                        break;
                    case DbExpressionType.Min:
                        break;
                    case DbExpressionType.OrderBy:
                    case DbExpressionType.OrderByDescending:
                        info.OrderExpressions.Enqueue(dbExpression);
                        break;
                    case DbExpressionType.Select:
                        info.SelectExpression = ((SelectDbExpression) dbExpression).Selector;
                        break;
                    case DbExpressionType.SelectMany: //todo 
                        var se = dbExpression as SelectManyDbExpression;
                        info.SelectExpression = se.Selector;
                        var lmd = info.SelectExpression as LambdaExpression;
                        if (info.joinCount++ == 0)
                            info.cache.GetTableAlias(lmd.Parameters[0]);
                        info.cache.GetTableAlias(lmd.Parameters[1]);

                        info.JoinExpressions.Enqueue(new JoinDbExpression
                                                         {
                                                             JoinType = JoinType.CrossJoin,
                                                             InnerKeySelector = lmd.Parameters[1],
                                                             OuterKeySelector = lmd.Parameters[0]
                                                         });
                        break;
                    case DbExpressionType.Single:
                    case DbExpressionType.SingleOrDefault:
                        info.Take = 1;
                        info.WhereExpression.Enqueue(((SingleDbExpression) dbExpression).Predicate);
                        break;
                    case DbExpressionType.Skip:
                        info.Skip = ((SkipDbExpression) dbExpression).Count;
                        break;
                    case DbExpressionType.Sum:
                        break;
                    case DbExpressionType.Take:
                        info.Take = ((TakeDbExpression) dbExpression).Count;
                        break;
                    case DbExpressionType.ThenBy:
                    case DbExpressionType.ThenByDescending:
                        info.OrderExpressions.Enqueue(dbExpression);
                        break;
                    case DbExpressionType.Where:
                        info.WhereExpression.Enqueue(((WhereDbExpression) dbExpression).Predicate);

                        break;
                    case DbExpressionType.Insert:
                        info.InsertExpression = dbExpression as InsertDbExpression;
                        break;
                    case DbExpressionType.Delete:
                        info.DeleteExpression = dbExpression;
                        break;
                    case DbExpressionType.Update:
                        info.UpdateExpression = dbExpression;
                        break;

                    default:
                        throw new ArgumentOutOfRangeException("dbExpressions");
                }
            }
            if (info.InsertExpression == null && info.DeleteExpression == null && info.UpdateExpression == null &&
                info.SelectExpression == null && !info.IsCount) //string.IsNullOrEmpty(info.CountString)
            {
                info.SelectExpression = Expression.Constant(info.SourceType);

                //throw new NotSupportedException("SelectExpression 不能为空");
            }
            if (info.SelectExpression != null)
            {
                var lmd = (info.SelectExpression as LambdaExpression);
                if (lmd != null)
                    info.ResultType = lmd.Body.Type;

                var cons = (info.SelectExpression as ConstantExpression);
                if (cons != null)
                    info.ResultType = cons.Value as Type;
            }
            if (info.IsCount)
            {
                info.OrderExpressions.Clear();
            }
            return info;
        }
    }
}